Blog

Gavin Pickin

September 05, 2017

Spread the word


Share your thoughts

First Docker Compose File

The roadshow has just started, and you might have learned what Docker is, why you could / should use it, and then maybe a little of how to use it. You can spin up a Docker container pretty easily, with a command or two, but usually, we work with multiple servers. Configuring that might be confusing at first... you might wonder, if i spin up 3 containers, how do they know how to find each other, and other questions like this, are easily solved, with Compose files. That is what we're going to look at today.

If you want to see more of the Ortus Solutions Container / Docker Roadshow, check out our event page here

Wait a minute, i just learned about Docker files, and now I need to worry about Docker Compose files too? Yes, and I'll tell you why.

Each server / container you spin up has a series of information stored in their dockerfile... but your project, how each of those pieces work together is contained in the Docker Compose file.

Lets look at a couple of scenarios, and see how we could setup our Docker Compose file.

1 - Basic CFML Container

We could do this with a simple docker file, but this is just the beginner of our scenario, so we'll start with a docker compose file. Let's look at the file, and then break down how it works

version: "3"

services:
 # CFML Engine
 cfml:
   image: ortussolutions/commandbox  
   # bind public port to 8080
   ports:
     - "8080:8080"
   volumes:
     - ./www:/app

Note: docker-compose.yml is a Yaml file, and therefore formatting is part of the code. The wrong level of indentation does make a difference.

  • Version 3 - This is the Docker Compose version we are using.
  • Services - this is a structure listing all the services we are managing with this compose files
  • CFML is the first service we are describing
    • Image - this is the docker image we are using as our base image for this service. Ortus's commandbox image is power packed, and is the perfect cfml image.
    • Ports - You need a way to get from your local machine to the docker container, so we're mapping port 8080 on our local to 8080 in the docker container. First port is the local port, second port is in the container. This gets important as you have more services you wish to connect with. Inside the container, Commandbox always runs on 8080... but you can map them to anything you want locally.
    • Volumes - this is where you map code on your machine, into the container. Here, we are mapping the www folder in this folder that contains the docker-compose.yml file into the app folder. As we change the code in the www folder, it updates in the container. Its a smooth workflow.

In this scenario, thats all we need. There are options through CommandBox with CFConfig for creating Lucee and Adobe ColdFusion settings for passwords, datasources etc, but we'll keep it as simple as we can for these examples.

Code? What does the www folder look like? Let's look at the whole directory structure

/
/www/
/www/index.cfm
docker-compose.yaml

Index.cfm has this code in this example

1-basicCFML - #now()#

We spin up this container from the command line with the following command from the root of our project

docker-compose up

When the command has completed, you will see a series of debug statements in the command line, and when you visit http://127.0.0.1:8080/ you will see this output

1-basicCFML - {ts '2017-09-05 01:40: 53'}

In the command line, press ctrl-c to kill the docker-compose setup. You can start docker-compose in daemon mode just like a normal docker file startup, with -d. If you start in daemon mode, you can stop / restart with the docker ps commands. More about that in another blog post.

2 - CFML Container with MySQL Server

It is hard to imagine running a CFML Server without need of a database, so the next scenario, we'll show you how to set up a mysql container to go with the cfml container from the last scenario. Here is the new combined docker-compose.yml

version: "3"

services:
  # CFML Engine
  cfml:
    image: ortussolutions/commandbox  
    # bind public port to 8080
    ports:
      - "8080:8080"
    volumes:
      - ./www:/app
      
  # MySQL Server
  mysql:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: "myp@ssword"

The first piece is the same, but we have a 2nd service described, mysql.

  • image - the image is the mysql image, distributed by mysql, available from Dockerhub.
  • environment - this is where you can pass in environmental variables to modify the containers behavior to suit your needs.
    • MYSQL_ROOT_PASSWORD - the password for mysql's root account. Important for security purposes not to be the default.

Code? What does the www folder look like? Let's look at the whole directory structure

/
/www/
/www/Application.cfc
/www/index.cfm
docker-compose.yaml

Application.cfc has this code in this example - essentially an empty Application.cfc with a datasource definition using the password set for mysql in the docker-compose.yml file.

component {
	this.datasources["dsmysql"] = {
		  class: 'org.gjt.mm.mysql.Driver'
		, connectionString: 'jdbc:mysql: //mysql:3306/mysql?useUnicode=true&characterEncoding=UTF-8&useLegacyDatetimeCode=true'
		, username: 'root'
		, password: "encrypted:744d34f22944e1ca2e92bbf13f2617f7fc4c7daa255e440e9c52d856af118228"
	};	
}

Index.cfm has this code in this example


select * from user



We spin up this container from the command line with the following command from the root of our project

docker-compose up

When the command has completed, when you visit http://127.0.0.1:8080/ you will see a dump of the user table.

By default, docker-compose.yml automatically does some basic networking, so our example works using the name of the container mysql for the url. You have more networking options available with Docker-compose, but its nice that as simple as this file is, you have 2 containers up and running, communicating, with a few lines of code.

If you want to be able to connect to the mysql server from your local machine, you can add ports like we did with the CFML engine.

ports: 
      - "33306:3306"

Now if you want to connect, you can access on 33306, which routes to the docker containers' 3306 port.

The MySQL image allows for you to select a database, load data on the first load, so you seed your database, and much more.

In the command line, press ctrl-c to kill the docker-compose setup. You can start docker-compose in daemon mode just like a normal docker file startup, with -d. If you start in daemon mode, you can stop / restart with the docker ps commands. More about that in another blog post.

What's next?

Check out an upcoming blog post with the next scenarios, where we'll keep adding to our existing setup. In that blog post we will learn about the following:

  • Put Nginx in front of the CFML Server and MySQL

  • Create a new DB and preload some data into the MySQL server

Clone the repo and try it out

Clone the repo, and pick your flavor, and spin up your own dev environment today.

https://github.com/Ortus-Solutions/firstDockerCompose

There are a lot more options, tune into the roadshow blogs and webinars to learn more.

Add Your Comment

(1)

Oct 10, 2018 10:55:27 UTC

by Didier

Hi Gavin, Very nice post. May I suggest two very little changes in : "2 - CFML Container with MySQL Server" ... # MySQL Server mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: "myp@ssword" and connectionString: 'jdbc:mysql://mysql:3306/mysql?useSSL=false&requireSSL=false&useUnicode=true&characterEncoding=UTF-8&useLegacyDatetimeCode=true'

Recent Entries

12 days of BoxLang - Day 3: SocketBox!

12 days of BoxLang - Day 3: SocketBox!

As BoxLang continues evolving into a modern, high-performance, JVM-based runtime, real-time communication becomes essential for the applications we all want to build: dashboards, collaboration tools, notifications, live feeds, multiplayer features, and more.

That’s where SocketBox steps in — the WebSocket upgrade listener built to work seamlessly with CommandBox and the BoxLang MiniServer. ⚡

Today, for Day 3, we’re highlighting how SocketBox supercharges BoxLang development by giving you fast, flexible, and framework-agnostic WebSocket capabilities.

Maria Jose Herrera
Maria Jose Herrera
December 12, 2025
12 Days of BoxLang - Day 2: CommandBox

12 Days of BoxLang - Day 2: CommandBox

BoxLang + CommandBox: The Enterprise Engine Behind Your Deployments

For Day 2 of our 12 Days of Christmas series, we’re diving into one of the most powerful parts of the BoxLang ecosystem: CommandBox the defacto enterprise servlet deployment platform for BoxLang.

If BoxLang is the language powering your applications, CommandBox is the engine room behind it all. ⚙️

Victor Campos
Victor Campos
December 11, 2025
12 Days of BoxLang - Day 1: ColdBox

12 Days of BoxLang - Day 1: ColdBox

ColdBox + BoxLang: The Future of Modern MVC on the JVM Welcome to Day 1 of the 12 Days of BoxLang

To kick off the series, we’re starting with one of the most powerful combinations in the Ortus ecosystem: ColdBox + BoxLang.

ColdBox has been the standard for modern CFML MVC development for over a decade. BoxLang is the next-generation dynamic language built for JVM and beyond. Together, they reshape how developers build web apps, APIs, microservices, CLIs, and soon desktop applications.

Let’s dive into why ColdBox 8 + BoxLang PRIME is a major milestone for the future of modern application development.

Maria Jose Herrera
Maria Jose Herrera
December 10, 2025